import json
import os
from datetime import datetime
from decimal import Decimal

from alipay import AliPay
from django.conf import settings
from django.db import transaction
from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework.response import Response
from rest_framework.views import APIView

from mall_web.apps.goods.models import SKU
from .models import OrderInfo, OrderGoods,Payment
from ..users.models import Address


# 1.订单中生成
class CartSettlementView(APIView):
    def get(self,request): # noqa
        # 昨天问思绪中有什么？今天知道了，就是哪些问题。有哪些框架中的问题。
        # 1.问题一：输出是什么？skus的列表数据，加一个运费
        # 2.处理逻辑是什么？,需要redis中的hash和集合的操作框架
        redis_client = get_redis_connection("cart")
        cart = redis_client.hgetall("cart_%s" % request.user.id)
        cart = {int(key): int(value) for key, value in cart.items()}
        cart_selected_skus = redis_client.smembers("cart_selected_%s" % request.user.id)
        # 3.框架来到django中的orm的操作
        skus = SKU.objects.filter(id__in=cart_selected_skus)
        skus_list = []
        for sku in skus:
            sku = sku.to_dict()
            sku["count"] = cart[sku["id"]]
            skus_list.append(sku)

        data = {
            "skus": skus_list,
            "freight": Decimal('10.00')
        }
        return Response(data)


# 2.去结算，生成订单
class CreateOrderView(APIView):
    def post(self, request): # noqa
        # 这个接口需要回答的问题
        # 问题一：django中关于事务如何操作。
        # 问题二：什么表要做什么操作？
        # 问题三：资源竞争，如何开启乐观锁
        # 问题四：mysql中的事务如何修改操作

        # 获取数据
        address = request.data.get("address")
        pay_method = request.data.get("address")
        user = request.user
        order_id = datetime.now().strftime('%Y%m%d%H%M%S')+'%06d' % user.id
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                # 表操作
                # 创建order_goods表
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=Address.objects.get(id=address),
                    total_count=0,
                    total_amount=0,
                    freight=Decimal(10),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM["UNSEND"] if pay_method == OrderInfo.PAY_METHODS_ENUM["CASH"]
                                                        else OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
                )
                # 从redis中拿数据
                redis_client = get_redis_connection("cart")
                cart = redis_client.hgetall("cart_%s" % user.id)
                cart = {int(key): int(value) for key,value in cart.items()}
                selected_skus_id = redis_client.smembers("cart_selected_%s"%user.id)
                # 遍历操作sku数据表数据

                for sku_id in selected_skus_id:
                    while True:
                        # 操作SKU表数据
                        sku = SKU.objects.get(id=sku_id)
                        old_stock = sku.stock
                        old_sales = sku.sales
                        cart_count = cart[sku.id]
                        if old_stock < cart_count:
                            return Response({"message":"库存不足"}, status=400)
                        new_stock = old_stock-cart_count
                        new_sales = old_sales+cart_count
                        ret = SKU.objects.filter(id=sku_id,stock=old_stock).update(stock=new_stock,sales=new_sales)
                        if ret == 0:
                            continue
                        # 修改spu中总销量
                        sku.goods.sales += cart_count
                        sku.goods.save()
                        # 操作orderInfo中的参数
                        order.total_count += cart_count
                        order.total_amount += sku.price * cart_count
                        # 操作order good中的参数
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=cart_count,
                            price=sku.price
                        )
                        break
                order.total_amount += order.freight
                order.save()
            except BaseException as e: # noqa
                transaction.savepoint_rollback(save_point)
                print(e)
                return Response({"message": "数据处理错误"}, status=400)
            else:
                transaction.savepoint_commit(save_point)
                # 删除redis中的数据
                redis_client.hdel("cart_%s" % user.id, *selected_skus_id)
                redis_client.srem("cart_selected_%s" % user.id,*selected_skus_id)
                return Response({
                    "order_id":order_id
                })


# 3.返回支付链接
class PayMentView(APIView):

    def get(self,request,order_id):

        # 判断order_id有效性
        try:
            order=OrderInfo.objects.get(user=request.user,order_id=order_id,pay_method=2,status=1)
        except:
            return Response({'errors':'无效订单'},status=405)

        # 支付对象初始化生成
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'keys/app_private_key.pem'),
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'keys/alipay_public_key.pem'),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug = settings.ALIPAY_DEBUG # 默认False
        )

        # 生成连接中的查询字符串参数
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id, # 订单编号
            total_amount=str(order.total_amount), # 订单总价
            subject='美多商城%s'%order_id, # 标题
            return_url="http://www.meiduo.site:8080/pay_success.html", # 跳转回美多的网址
        )

        # 生成跳转连接

        alipay_url=settings.ALIPAY_URL+order_string

        return Response({'alipay_url':alipay_url})


# 4.记录支付返回id和订单id的表
class PaymentSaveView(APIView):
    def put(self,request):
        # 获取前端信息
        data=request.query_params.dict()
        # sign 不能参与签名验证
        signature = data.pop("sign")

        # 支付对象初始化生成
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys/app_private_key.pem'),
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                                'keys/alipay_public_key.pem'),
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=settings.ALIPAY_DEBUG  # 默认False
        )

        # 验证数据是否是支付宝发送过来的
        success = alipay.verify(data, signature)

        if success:
            # 获取order_id
            order_id=data['out_trade_no']
            # 获取支付宝交易流水号
            trade_id=data['trade_no']
            # 绑定操作
            Payment.objects.create(order_id=order_id,trade_id=trade_id)

            # 修改订单状态
            OrderInfo.objects.filter(order_id=order_id).update(status=2)
            return Response({'trade_id':trade_id})


        else:
            return Response({'errors':'无效支付宝信息'},status=405)